﻿using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using MicrobloggingInterface;

namespace HexunMicroblogging
{
    class Issue
    {
        #region Private fields

        /// <summary>
        /// Configure file for loading and accessing via Linq To Xml.
        /// </summary>
        private string configFile = string.Empty;

        /// <summary>
        /// Indicate if need credential for issuing microblogging messages.
        /// </summary>
        private bool needCredential = false;

        /// <summary>
        /// Indicate the endpoint address of Issue interface.
        /// </summary>
        private string endpointAddress = string.Empty;

        /// <summary>
        /// Indicate the response data type: Xml or Json.
        /// </summary>
        private string responseDataType = string.Empty;

        /// <summary>
        /// Response content.
        /// </summary>
        private string responseContent = string.Empty;

        /// <summary>
        /// Indicate the HTTP request method.
        /// </summary>
        private string requestMethod = string.Empty;

        /// <summary>
        /// Indicate an array of required parameters.
        /// </summary>
        private string[] arrRequiredParameter = null;

        /// <summary>
        /// Indicate the application key for request.
        /// </summary>
        private string appKey = string.Empty;

        /// <summary>
        /// Account user name.
        /// </summary>
        private string userName = string.Empty;

        /// <summary>
        /// Account password.
        /// </summary>
        private string password = string.Empty;

        #endregion

        #region Public fields

        /// <summary>
        /// Expose field.
        /// </summary>
        public bool NeedCredential
        {
            get { return needCredential; }
        }

        /// <summary>
        /// Response data type.
        /// </summary>
        public DataType ResponseDataType
        {
            get
            {
                if (responseDataType.Equals("Xml"))
                {
                    return DataType.Xml;
                }

                if (responseDataType.Equals("Json"))
                {
                    return DataType.Json;
                }

                return DataType.Unknow;
            }
        }

        /// <summary>
        /// Public field of responseConent.
        /// </summary>
        public string ResponseContent
        {
            get { return responseContent; }
        }

        #endregion

        #region Public methods

        public void SetCredential(string userName, string password)
        {
            this.userName = userName;
            this.password = password;
        }

        public Issue(string configFile)
        {
            // TODO: Complete member initialization
            this.configFile = configFile;
        }

        public bool LoadConfig()
        {
            XNamespace ns = "https://dennisandslowquiet.micorblogging.hexun.com/ConfigureSchema";
            XElement root = XElement.Load(configFile);
            
            var issue = from el in root.Elements(ns + "microbloggingApi").Elements(ns + "issue")
                        select el;
            XElement elIssue = issue.ElementAt(0);

            needCredential = bool.Parse(elIssue.Element(ns + "needCredential").Value);
            endpointAddress = elIssue.Element(ns + "endpoint").Element(ns + "address").Value;
            responseDataType = elIssue.Element(ns + "endpoint").Element(ns + "type").Value;
            requestMethod = elIssue.Element(ns + "requestMethod").Value;

            /*
            var requiredParameter = from el in elIssue.Elements(ns + "parameters").Elements(ns + "parameter")
                                    where (string)(el.Attribute("required").Value) == "True"
                                    select el;
            */
            var requiredParameter = from el in elIssue.Descendants(ns + "parameter")
                                    where (string)(el.Attribute("required").Value) == "True"
                                    select el.Value;
            arrRequiredParameter = requiredParameter.ToArray<string>();

            var appKeyArray = from el in root.Descendants(ns + "appKey")
                              select el.Value;
            appKey = appKeyArray.ToArray<string>()[0];

            return true;
        }

        public bool DoIssue(string textData, out string issueErrorMessage)
        {
            issueErrorMessage = string.Empty;

            if (needCredential && (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password)))
            {
                return false;
            }

            string usernamePassword = userName + ":" + password;

            // URI and data for post.
            string url = string.Empty;
            url = endpointAddress + responseDataType.ToLower();

            // The real date for send.
            string data = "content=" + System.Web.HttpUtility.UrlEncode(textData);
            data += "&appkey=" + appKey;

            // Declare WebRequest instance.
            System.Net.WebRequest webRequest = System.Net.WebRequest.Create(url);
            System.Net.HttpWebRequest httpRequest = webRequest as System.Net.HttpWebRequest;

            // Prepare credential.
            System.Net.CredentialCache myCache = new System.Net.CredentialCache();
            myCache.Add(new Uri(url), "Basic", new System.Net.NetworkCredential(userName, password));
            httpRequest.Credentials = myCache;
            //httpRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.GetEncoding("GB2312").GetBytes(usernamePassword)));
            httpRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new System.Text.UTF8Encoding().GetBytes(usernamePassword)));

            // Issue post request.
            httpRequest.Method = requestMethod;
            httpRequest.ContentType = "application/x-www-form-urlencoded";

            byte[] bytesToPost = System.Text.Encoding.GetEncoding("GB2312").GetBytes(data);
            httpRequest.ContentLength = bytesToPost.Length;

            System.IO.Stream requestStream = null;
            try
            {
                requestStream = httpRequest.GetRequestStream();
                requestStream.Write(bytesToPost, 0, bytesToPost.Length);
            }
            catch (WebException we)
            {
                issueErrorMessage = we.Message;
                return false;
            }
            catch (Exception ex)
            {
                issueErrorMessage = "Unknown Error!";

                // Log...
                string log = ex.Message;

                return false;
            }
            finally
            {
                if (requestStream != null)
                {
                    requestStream.Close();
                    requestStream.Dispose();
                }
            }

            // Get resopose.
            try
            {
                System.Net.WebResponse wr = httpRequest.GetResponse();
                System.IO.Stream receiveStream = wr.GetResponseStream();
                using (System.IO.StreamReader reader = new System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8))
                {
                    responseContent = reader.ReadToEnd();
                }
            }
            catch (WebException we)
            {
                issueErrorMessage = we.Message;
                return false;
            }
            catch (Exception ex)
            {
                issueErrorMessage = "Unknown Error!";

                // Log...
                string log = ex.Message;

                return false;
            }

            return true;
        }

        #endregion
    }
}
